#include "lcd_init.h"
#include "stdio.h"
#include <string.h>
// #include "app.h"

typedef void (*FunType)(void);
//**********************************write function begin********************************************
void wr_cmd_4spi_8bcs(uint8_t par)
{
    LCD_DCXLow();
    LCD_CSLow();

    LCD_SCLLow();
    if (par & 0x80)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x40)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x20)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x10)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x08)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x04)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x02)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x01)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_CSHigh();
    // LCD_DCXHigh();
    // HAL_Delay(5);
}
void wr_dat_4spi_8bcs(uint8_t par)
{
    LCD_DCXHigh();
    LCD_CSLow();

    LCD_SCLLow();
    if (par & 0x80)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x40)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x20)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x10)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x08)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x04)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x02)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_SCLLow();
    if (par & 0x01)
        LCD_SDAHigh();
    else
        LCD_SDALow();
    LCD_SCLHigh();

    LCD_CSHigh();
    LCD_DCXHigh();
    // HAL_Delay(1);
}
void wr_cmd_parall1_8(uint16_t par)
{
    LCD_DCXLow();
    LCD_CSLow();
    LCD_WRLow();
    GPIOB->ODR = par;

    LCD_WRHigh();
}
void wr_dat_parall1_8(uint16_t par)
{
    LCD_DCXHigh();
    LCD_WRLow();
    GPIOB->ODR = par;

    LCD_WRHigh();
}
void wr_cmd_parall2_8(uint16_t par)
{
    LCD_DCXLow();
    LCD_CSLow();
    LCD_WRLow();
    GPIOB->ODR = par << 1;

    LCD_WRHigh();
}
void wr_dat_parall2_8(uint16_t par)
{
    LCD_DCXHigh();
    LCD_WRLow();
    GPIOB->ODR = par << 1;

    LCD_WRHigh();
}
//**********************************read function begin********************************************
void pb_out(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // db 0-7
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
                          GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void pb_in(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // db 0-7
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
                          GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
uint8_t i801_read_byte(void)
{
    uint8_t v;

    LCD_DCXHigh();
    LCD_RDLow();
    v = GPIOB->IDR;
    LCD_RDHigh();

    return v;
}
void rd_parall1_8(uint8_t c, uint8_t *d, uint32_t l)
{
    uint8_t buf[128];

    wr_cmd_parall1_8(c);
    pb_in();
    for (int i = 0; i < l; i++)
    {
        buf[i] = i801_read_byte();
    }
    LCD_CSHigh();
    pb_out();
    memcpy(d, buf, l);
}
//**********************************write display begin********************************************
void wr_displ_parall1_8(uint8_t color)
{
    LCD_DCXHigh();
    LCD_WRLow();
    GPIOB->ODR = color;
    LCD_WRHigh();
}
void wr_displ_parall2_18(uint16_t color1, uint16_t color2)
{
    LCD_DCXHigh();
    LCD_WRLow();
    if (color1 & 0x02)
        HAL_GPIO_WritePin(DB17_GPIO_Port, DB17_Pin, GPIO_PIN_SET);
    else
        HAL_GPIO_WritePin(DB17_GPIO_Port, DB17_Pin, GPIO_PIN_RESET);
    if (color1 & 0x01)
        HAL_GPIO_WritePin(DB16_GPIO_Port, DB16_Pin, GPIO_PIN_SET);
    else
        HAL_GPIO_WritePin(DB16_GPIO_Port, DB16_Pin, GPIO_PIN_RESET);
    GPIOB->ODR = color2;
    LCD_WRHigh();
}

void sda_state(uint8_t state)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if (state == 0)
    {
        GPIO_InitStruct.Pin = SPI1_MOSI_Pin;
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(SPI1_MOSI_GPIO_Port, &GPIO_InitStruct);
    }
    else if (state == 1)
    {
        GPIO_InitStruct.Pin = SPI1_MOSI_Pin;
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(SPI1_MOSI_GPIO_Port, &GPIO_InitStruct);
    }
}

void test_delay(void)
{
    while (1)
    {
        HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_SET);
        HAL_Delay(1000);
        HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_RESET);
        HAL_Delay(1000);
    }
}

void wr_spi(uint8_t dc, uint8_t par)
{
    sda_state(io_writ);
    LCD_CSLow();
    if (dc == Command)
    {
        LCD_DCXLow();
    }
    else
    {
        LCD_DCXHigh();
    }

    for (uint8_t i = 0; i < 8; i++)
    {
        LCD_SCLLow();
        if (par & 0x80)
        {
            LCD_SDAHigh();
        }
        else
        {
            LCD_SDALow();
        }
        par = par << 1;
        LCD_SCLHigh();
    }
    LCD_DCXHigh();
}

uint8_t rd_spi(uint8_t reg)
{
    sda_state(io_writ);
    uint8_t re_val = 0;
    uint8_t addr = reg;
    int i = 0;

    LCD_DCXLow();
    LCD_CSLow();

    for (i = 0; i < 8; i++)
    {
        LCD_SCLLow();
        if (reg & 0x80)
        {
            LCD_SDAHigh();
        }
        else
        {
            LCD_SDALow();
        }
        reg = reg << 1;
        LCD_SCLHigh();
    }
    sda_state(io_read);
    for (i = 0; i < 8; i++)
    {
        LCD_SCLLow();
        re_val = re_val << 1;
        re_val = re_val + HAL_GPIO_ReadPin(SPI1_MOSI_GPIO_Port, SPI1_MOSI_Pin);
        LCD_SCLHigh();
    }
    LCD_CSHigh();
    printf("reg %02x is %02X\n\r", addr, re_val);

    sda_state(io_writ);

    return re_val;
}

void Write(uint8_t dc, uint8_t par)
{
    /*
    if (dc == Command)
    {
        wr_cmd_4spi_8bcs(par);
    }
    else if (dc == Parameter)
    {
        wr_dat_4spi_8bcs(par);
    }
    */
    wr_spi(dc, par);
}

void fullcolor(uint8_t color1, uint8_t color2, uint8_t color3)
{
    uint32_t totalpoint = 240;
    totalpoint *= 320;
    wr_cmd_4spi_8bcs(0x2A);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0xEF);
    wr_cmd_4spi_8bcs(0x2B);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x01);
    wr_dat_4spi_8bcs(0x3F);
    wr_cmd_4spi_8bcs(0x2c);

    for (uint32_t i = 0; i < totalpoint; i++)
    {

        wr_dat_4spi_8bcs(color1);
        wr_dat_4spi_8bcs(color2);
        wr_dat_4spi_8bcs(color3);
    }
}

void HW_Reset(void)
{
    LCD_RSTHigh();
    HAL_Delay(120);
    LCD_RSTLow();
    HAL_Delay(120);
    LCD_RSTHigh();
    HAL_Delay(200);
}

void Delay(uint32_t ms)
{
    HAL_Delay(ms);
}

uint8_t rd_otp(void)
{
    uint8_t id1, id2, id3, idtimes = 0;
    uint8_t otp_result = 0;
    id1 = rd_spi(0xDA);
    id2 = rd_spi(0xDB);
    id3 = rd_spi(0xDC);
    idtimes = rd_spi(0xCA);
    if ((id1 == 0x85) & (id2 == 0x85) & (id3 == 0x52))
    {
        printf("No OTP is defult ID\n\r");
        otp_result = 2;
    }
    else if ((id1 == OTP_ID1) & (id2 == OTP_ID2) & (id3 == OTP_ID3))
    {
        printf("Has been OTP\n\r");
        otp_result = 1;
    }
    else
    {
        printf("Something is wrong\n\r");
        otp_result = 0;
    }
    return otp_result;
}

void OTP_initial(void)
{
    //==Supply VPP=7.5V==//
    HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_SET);
    HAL_Delay(200);
    Write(Command, 0xDF);
    Write(Parameter, 0x5A);
    Write(Parameter, 0x69);
    Write(Parameter, 0x02);
    Write(Parameter, 0x01);
    Write(Command, 0xFA);
    Write(Parameter, 0x5A);
    Write(Parameter, 0x69);
    Write(Parameter, 0xEE);
    Write(Parameter, 0x04);
    Write(Command, 0xEC);
    Write(Parameter, 0x01);
    Write(Command, 0xFC);
    Write(Parameter, 0x0C);
    Write(Parameter, 0x2C);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x0D);
    Write(Parameter, OTP_ID1); // Id1
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x0E);
    Write(Parameter, OTP_ID2); // ID2
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x0F);
    Write(Parameter, OTP_ID3); // ID3
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x10);
    Write(Parameter, 0x01);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x11);
    Write(Parameter, 0xFF);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x12);
    Write(Parameter, 0x0b);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x13);
    Write(Parameter, 0x20);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x14); // C5:VCOM setting
    Write(Parameter, 0x20);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x15);
    Write(Parameter, 0x0F);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x16);
    Write(Parameter, 0x00);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFC);
    Write(Parameter, 0x17);
    Write(Parameter, 0x08);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xEC);
    Write(Parameter, 0x00);
    Write(Command, 0xFC);
    Write(Parameter, 0x01);
    Write(Parameter, 0xFD);
    Write(Command, 0xFE);
    Write(Parameter, 0x29);
    Write(Parameter, 0xA5);
    Delay(10);
    Write(Command, 0xFA);
    Write(Parameter, 0x5A);
    Write(Parameter, 0x69);
    Write(Parameter, 0xEE);
    Write(Parameter, 0x00);
    Write(Command, 0xDF);
    Write(Parameter, 0x5A);
    Write(Parameter, 0x69);
    Write(Parameter, 0x02);
    Write(Parameter, 0x00);

    HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_RESET);
    HAL_Delay(200);
    // Remove VPP//
}

void OTP_main(void)
{
    uint8_t otp_state = 0;
    HW_Reset();
    otp_state = rd_otp();
    if (otp_state != 1)
    {
        printf("ID is wrong");
        OTP_initial();
        HW_Reset();
        otp_state = rd_otp();
        if (otp_state != 1)
        {
            printf("OTP NG\n\r");
            initial();
            fullcolor(0xFF, 0x00, 0x00);
            while (1)
            {
                /* code */
            }
        }
        else
        {
            initial();
            fullcolor(0x00, 0xFF, 0x00);
            HAL_Delay(1000);
        }
    }
    else
    {
        initial();
        fullcolor(0x00, 0xFF, 0x00);
        HAL_Delay(1000);
    }
}

void initial(void)
{
    HW_Reset();

    Delay(120);

    Write(Command, 0x11);

    Delay(120);

    Write(Command, 0x36);
    Write(Parameter, 0x00);

    Write(Command, 0x3A);
    Write(Parameter, 0x06);

    Write(Command, 0xB2);
    Write(Parameter, 0x0C);
    Write(Parameter, 0x0C);
    Write(Parameter, 0x00);
    Write(Parameter, 0x33);
    Write(Parameter, 0x33);

    Write(Command, 0xB7);
    Write(Parameter, 0x71);

    Write(Command, 0xBB);
    Write(Parameter, 0x36);

    Write(Command, 0xC0);
    Write(Parameter, 0x2C);

    Write(Command, 0xC2);
    Write(Parameter, 0x01);

    Write(Command, 0xC3);
    Write(Parameter, 0x13);

    Write(Command, 0xC4);
    Write(Parameter, 0x20);

    Write(Command, 0xC5);
    Write(Parameter, 0x1E);
    
    Write(Command, 0xC6);
    Write(Parameter, 0x0F);

    Write(Command, 0xD0);
    Write(Parameter, 0xA4);
    Write(Parameter, 0xA1);

    Write(Command, 0xD6);
    Write(Parameter, 0xA1);

    Write(Command, 0xE0);
    Write(Parameter, 0xF0);
    Write(Parameter, 0x08);
    Write(Parameter, 0x0D);
    Write(Parameter, 0x08);
    Write(Parameter, 0x08);
    Write(Parameter, 0x04);
    Write(Parameter, 0x2A);
    Write(Parameter, 0x43);
    Write(Parameter, 0x40);
    Write(Parameter, 0x37);
    Write(Parameter, 0x12);
    Write(Parameter, 0x12);
    Write(Parameter, 0x28);
    Write(Parameter, 0x30);

    Write(Command, 0xE1);
    Write(Parameter, 0xF0);
    Write(Parameter, 0x0A);
    Write(Parameter, 0x0E);
    Write(Parameter, 0x0A);
    Write(Parameter, 0x09);
    Write(Parameter, 0x26);
    Write(Parameter, 0x29);
    Write(Parameter, 0x33);
    Write(Parameter, 0x40);
    Write(Parameter, 0x38);
    Write(Parameter, 0x14);
    Write(Parameter, 0x15);
    Write(Parameter, 0x2A);
    Write(Parameter, 0x31);

    Write(Command, 0x21);

    Write(Command, 0x29);

    Write(Command, 0x2C);
}

void initial_old(void)
{
    // test_delay();
    // HW_Reset();

    Delay(120);

    Write(Command, 0x11);

    // rd_otp();

    Delay(120);

    Write(Command, 0x36);
    Write(Parameter, 0x00);

    Write(Command, 0x3A);
    Write(Parameter, 0x06);

    Write(Command, 0xB2);
    Write(Parameter, 0x0C);
    Write(Parameter, 0x0C);
    Write(Parameter, 0x00);
    Write(Parameter, 0x33);
    Write(Parameter, 0x33);

    Write(Command, 0xB7);
    Write(Parameter, 0x71);

    Write(Command, 0xBB);
    Write(Parameter, 0x3B);

    Write(Command, 0xC0);
    Write(Parameter, 0x2C);

    Write(Command, 0xC2);
    Write(Parameter, 0x01);

    Write(Command, 0xC3);
    Write(Parameter, 0x13);

    Write(Command, 0xC4);
    Write(Parameter, 0x20);

    Write(Command, 0xC6);
    Write(Parameter, 0x0F);

    Write(Command, 0xD0);
    Write(Parameter, 0xA4);
    Write(Parameter, 0xA1);

    Write(Command, 0xD6);
    Write(Parameter, 0xA1);

    Write(Command, 0xE0);
    Write(Parameter, 0xD0);
    Write(Parameter, 0x08);
    Write(Parameter, 0x0A);
    Write(Parameter, 0x0D);
    Write(Parameter, 0x0B);
    Write(Parameter, 0x07);
    Write(Parameter, 0x21);
    Write(Parameter, 0x33);
    Write(Parameter, 0x39);
    Write(Parameter, 0x39);
    Write(Parameter, 0x16);
    Write(Parameter, 0x16);
    Write(Parameter, 0x1F);
    Write(Parameter, 0x3C);

    Write(Command, 0xE1);
    Write(Parameter, 0xD0);
    Write(Parameter, 0x00);
    Write(Parameter, 0x03);
    Write(Parameter, 0x01);
    Write(Parameter, 0x00);
    Write(Parameter, 0x10);
    Write(Parameter, 0x21);
    Write(Parameter, 0x32);
    Write(Parameter, 0x38);
    Write(Parameter, 0x16);
    Write(Parameter, 0x14);
    Write(Parameter, 0x14);
    Write(Parameter, 0x20);
    Write(Parameter, 0x3D);

    Write(Command, 0x21);

    Write(Command, 0x29);

    Write(Command, 0x2C);
}

void C096LAB_Init(void)
{
    LCD_RSTHigh();
    HAL_Delay(120);
    LCD_RSTLow();
    HAL_Delay(120);
    LCD_RSTHigh();
    HAL_Delay(200);

    HAL_Delay(120); // HAL_Delay 120ms

    wr_cmd_4spi_8bcs(0x11); // Sleep out

    HAL_Delay(120); // HAL_Delay 120ms

    wr_cmd_4spi_8bcs(0xB1);
    wr_dat_4spi_8bcs(0x05);
    wr_dat_4spi_8bcs(0x3A);
    wr_dat_4spi_8bcs(0x3A);

    wr_cmd_4spi_8bcs(0xB2);
    wr_dat_4spi_8bcs(0x05);
    wr_dat_4spi_8bcs(0x3A);
    wr_dat_4spi_8bcs(0x3A);

    wr_cmd_4spi_8bcs(0xB3);
    wr_dat_4spi_8bcs(0x05);
    wr_dat_4spi_8bcs(0x3A);
    wr_dat_4spi_8bcs(0x3A);
    wr_dat_4spi_8bcs(0x05);
    wr_dat_4spi_8bcs(0x3A);
    wr_dat_4spi_8bcs(0x3A);

    wr_cmd_4spi_8bcs(0xB4); // Dot inversion
    wr_dat_4spi_8bcs(0x03);

    wr_cmd_4spi_8bcs(0xC0);
    wr_dat_4spi_8bcs(0x44);
    wr_dat_4spi_8bcs(0x04);
    wr_dat_4spi_8bcs(0x04);

    wr_cmd_4spi_8bcs(0xC1);
    wr_dat_4spi_8bcs(0xC0);

    wr_cmd_4spi_8bcs(0xC2);
    wr_dat_4spi_8bcs(0x0D);
    wr_dat_4spi_8bcs(0x00);

    wr_cmd_4spi_8bcs(0xC3);
    wr_dat_4spi_8bcs(0x8D);
    wr_dat_4spi_8bcs(0x6A);

    wr_cmd_4spi_8bcs(0xC4);
    wr_dat_4spi_8bcs(0x8D);
    wr_dat_4spi_8bcs(0xEE);

    wr_cmd_4spi_8bcs(0xC5);
    wr_dat_4spi_8bcs(0x14);

    wr_cmd_4spi_8bcs(0xE0);
    wr_dat_4spi_8bcs(0x06);
    wr_dat_4spi_8bcs(0x1C);
    wr_dat_4spi_8bcs(0x16);
    wr_dat_4spi_8bcs(0x16);
    wr_dat_4spi_8bcs(0x36);
    wr_dat_4spi_8bcs(0x2F);
    wr_dat_4spi_8bcs(0x28);
    wr_dat_4spi_8bcs(0x2A);
    wr_dat_4spi_8bcs(0x27);
    wr_dat_4spi_8bcs(0x24);
    wr_dat_4spi_8bcs(0x2C);
    wr_dat_4spi_8bcs(0x35);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x03);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x10);

    wr_cmd_4spi_8bcs(0xE1);
    wr_dat_4spi_8bcs(0x05);
    wr_dat_4spi_8bcs(0x1A);
    wr_dat_4spi_8bcs(0x0F);
    wr_dat_4spi_8bcs(0x0E);
    wr_dat_4spi_8bcs(0x2E);
    wr_dat_4spi_8bcs(0x2A);
    wr_dat_4spi_8bcs(0x24);
    wr_dat_4spi_8bcs(0x29);
    wr_dat_4spi_8bcs(0x29);
    wr_dat_4spi_8bcs(0x27);
    wr_dat_4spi_8bcs(0x2F);
    wr_dat_4spi_8bcs(0x3C);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x02);
    wr_dat_4spi_8bcs(0x02);
    wr_dat_4spi_8bcs(0x10);

    wr_cmd_4spi_8bcs(0x35);
    wr_dat_4spi_8bcs(0x00);

    wr_cmd_4spi_8bcs(0x3A); // 65k mode
    wr_dat_4spi_8bcs(0x66);

    wr_cmd_4spi_8bcs(0x36);
    wr_dat_4spi_8bcs(0xC0);

    wr_cmd_4spi_8bcs(0x29); // Display on

    wr_cmd_4spi_8bcs(0x2C);

    wr_cmd_4spi_8bcs(0x2A);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x00 + 2);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x7F + 2);
    wr_cmd_4spi_8bcs(0x2B);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x00 + 1);
    wr_dat_4spi_8bcs(0x00);
    wr_dat_4spi_8bcs(0x9F + 1);
}
